/*
 * Copyright © 2017 eqxiu.com 北京中网易企秀科技有限公司  All rights reserved.
 */
package cn.hermit.data.xml.handler;

import javax.xml.namespace.QName;

import cn.hermit.core.FastStack;
import cn.hermit.data.xml.model.XmlElement;
import cn.hermit.data.xml.factory.OrderedXmlFactory;
import cn.hermit.data.xml.model.XmlDocument;
import cn.hermit.data.xml.model.XmlFactory;

/**
 * Using steaming API to create XML Document.
 * 
 * <p>
 * Some cases requires to keep order of XML nodes or XML attributes.
 * The framework provides many factories to create various kinds of XML element, which keeps nodes or attributes order.
 * Please see the abstract class {@link XmlFactory XmlFactory}
 * and the package of {@link com.eqxiu.tiny.data.xml.factory various factories }
 * </p>
 *
 * @author Jack Gao (Chinese name : GAO JIANGUO, Email : linux.gjg@gmail.com)
 * @date 19 Jun, 2014
 */
public class XmlHandler implements ContentHandler {

	/**
	 * XML factory to create XML objects
	 */
	protected XmlFactory xmlFactory;

	private FastStack<XmlElement> stack;

	/**
	 * Constructor with a default ordered XmlFactory.
	 * 
	 */
	public XmlHandler() {
		this(new OrderedXmlFactory());
	}

	/**
	 * Constructor with a XmlFactory as parameter.
	 * 
	 * @param xmlFactory
	 * 		XML factory to create XML objects
	 */
	public XmlHandler(XmlFactory xmlFactory) {
		if (xmlFactory == null) {
			xmlFactory = new OrderedXmlFactory();
		}
		this.xmlFactory = xmlFactory;
		this.stack = new FastStack<XmlElement>();
		this.stack.push(this.xmlFactory.createDocument());
	}
	
	@Override
    public void startDocument() {
        
    }

	@Override
	public void version(String version) {
		XmlElement parent = this.stack.peek();
		if (XmlDocument.class.isInstance(parent)) {
			this.xmlFactory.version((XmlDocument) parent, version);
		}
	}

	@Override
	public void encoding(String encoding) {
		XmlElement parent = this.stack.peek();
		if (XmlDocument.class.isInstance(parent)) {
			this.xmlFactory.encoding((XmlDocument) parent, encoding);
		}
	}

	@Override
	public void standalone(String standalone) {
		XmlElement parent = this.stack.peek();
		if (XmlDocument.class.isInstance(parent)) {
			this.xmlFactory.standalone((XmlDocument) parent, standalone);
		}
	}

	@Override
	public void startElement(QName name, boolean closedTag) {
		XmlElement parent = this.stack.peek();
		XmlElement elem = this.xmlFactory.createElement(name, closedTag);
		if (XmlDocument.class.isInstance(parent)) {
			this.xmlFactory.root((XmlDocument) parent, elem);
		} else {
			this.xmlFactory.child(parent, elem, false);
		}
		this.stack.push(elem);
	}

	@Override
	public void attribute(QName name, String value) {
		XmlElement parent = this.stack.peek();
		this.xmlFactory.attribute(parent, name, value, false);
	}

	@Override
	public void text(String content) {
		XmlElement parent = this.stack.peek();
		this.xmlFactory.text(parent, content);
	}

	@Override
	public void cdata(String content) {
		XmlElement parent = this.stack.peek();
		this.xmlFactory.cdata(parent, content);
	}

	@Override
	public void comment(String content) {
		XmlElement parent = this.stack.peek();
		this.xmlFactory.comment(parent, content);

	}

	@Override
	public void endElement(QName name,boolean closedTag) {
		this.stack.pop();
	}
	
    @Override
    public void endDocument() {
        
    }

    /**
	 * @return
	 * 		XML Document after parsing
	 */
	public XmlDocument getDocument() {
		return (XmlDocument) this.stack.peek();
	}

	/**
	 * @return
	 * 		XML factory to create XML objects
	 */
	public XmlFactory getXmlFactory() {
		return this.xmlFactory;
	}

}